/*
 * // +-------------------------------------------------------------------------------------------------
 * // |                 有你就好 [ 有节骨乃坚，无心品自端 ]     <http://encoding.wang>
 * // +-------------------------------------------------------------------------------------------------
 * // |                             独在异乡为异客         每逢佳节倍思亲
 * // +-------------------------------------------------------------------------------------------------
 * // |                 联系:   <707069100@qq.com>      <http://weibo.com/513778937>
 * // +-------------------------------------------------------------------------------------------------
 */

// -----------------------------------------------------------------------------------------------------
// +----------------------------------------------------------------------------------------------------
// |                   ErYang出品 属于小极品          共同学习    共同进步
// +----------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------


package wang.encoding.mroot.admin.common.shiro


import org.apache.shiro.authc.credential.CredentialsMatcher
import org.apache.shiro.session.mgt.SessionManager
import org.apache.shiro.spring.LifecycleBeanPostProcessor
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor
import org.apache.shiro.spring.web.ShiroFilterFactoryBean
import org.apache.shiro.web.mgt.DefaultWebSecurityManager
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator
import org.springframework.boot.web.servlet.FilterRegistrationBean
import org.springframework.cache.annotation.EnableCaching
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.web.filter.DelegatingFilterProxy
import java.util.*
import javax.servlet.Filter

/**
 * shiro 配置
 *
 * @author ErYang
 */
@Configuration
@EnableCaching
class ShiroConfiguration {

    companion object {

        private val logger: Logger = LoggerFactory.getLogger(ShiroConfiguration::class.java)

        /**
         * 过滤器
         */
        private val filters = LinkedHashMap<String, Filter>()
        /**
         * 过滤规则
         */
        private val filterChainDefinitionMap = LinkedHashMap<String, String>()
    }

    // -------------------------------------------------------------------------------------------------

    val lifecycleBeanPostProcessor: LifecycleBeanPostProcessor
        @Bean(name = ["lifecycleBeanPostProcessor"])
        get() = LifecycleBeanPostProcessor()

    // -------------------------------------------------------------------------------------------------

    /**
     * 配置自定义的密码比较器
     */
    @Bean(name = ["credentialsMatcher"])
    fun credentialsMatcher(): CredentialsMatcher {
        return MyCredentialsMatcher()
    }

    // -------------------------------------------------------------------------------------------------

    /**
     * 配置自定义的权限登录器
     */
    @Bean(name = ["shiroDbRealm"])
    fun shiroDbRealm(): ShiroDbRealm {
        val shiroDbRealm = ShiroDbRealm()
        shiroDbRealm.credentialsMatcher = credentialsMatcher()
        return shiroDbRealm
    }

    // -------------------------------------------------------------------------------------------------

    /**
     * session管理器
     *
     * @return SessionManager
     */
    @Bean(name = ["sessionManager"])
    fun sessionManager(): SessionManager {
        val sessionManager = DefaultWebSessionManager()
        // 单位 毫秒  30分钟
        sessionManager.globalSessionTimeout = (30 * 60 * 1000).toLong()
        sessionManager.isDeleteInvalidSessions = true
        sessionManager.isSessionValidationSchedulerEnabled = true
        sessionManager.isDeleteInvalidSessions = true
        return sessionManager
    }

    // -------------------------------------------------------------------------------------------------

    /**
     * 配置核心安全事务管理器
     *
     * @return SecurityManager
     */
    @Bean(name = ["securityManager"])
    fun securityManager(): DefaultWebSecurityManager {
        val manager = DefaultWebSecurityManager()
        manager.setRealm(shiroDbRealm())
        manager.sessionManager = sessionManager()
        return manager
    }

    // -------------------------------------------------------------------------------------------------

    /**
     * 开启 shiro aop 注解支持
     * 使用代理方式 所以需要开启代码支持
     * Controller才能使用@RequiresPermissions
     *
     * @param securityManager SecurityManager
     * @return AuthorizationAttributeSourceAdvisor
     */
    @Bean
    fun authorizationAttributeSourceAdvisor(securityManager: DefaultWebSecurityManager): AuthorizationAttributeSourceAdvisor {
        val authorizationAttributeSourceAdvisor = AuthorizationAttributeSourceAdvisor()
        authorizationAttributeSourceAdvisor.securityManager = securityManager
        return authorizationAttributeSourceAdvisor
    }

    // -------------------------------------------------------------------------------------------------

    @Bean
    fun defaultAdvisorAutoProxyCreator(): DefaultAdvisorAutoProxyCreator {
        val defaultAdvisorAutoProxyCreator = DefaultAdvisorAutoProxyCreator()
        defaultAdvisorAutoProxyCreator.isProxyTargetClass = true
        return defaultAdvisorAutoProxyCreator
    }

    // -------------------------------------------------------------------------------------------------

    @Bean
    fun filterRegistrationBean(): FilterRegistrationBean<DelegatingFilterProxy> {
        val filterRegistration = FilterRegistrationBean<DelegatingFilterProxy>()
        val proxy = DelegatingFilterProxy("shiroFilter")
        //  该值缺省为 false 表示生命周期由 SpringApplicationContext 管理 设置为 true 则表示由 ServletContainer 管理
        proxy.setTargetFilterLifecycle(false)
        filterRegistration.filter = proxy
        //filterRegistration.setEnabled(true);
        // 可以自己灵活的定义很多 避免一些根本不需要被 shiro 处理的请求被包含进来
        filterRegistration.addUrlPatterns("/*")
        return filterRegistration
    }

    // -------------------------------------------------------------------------------------------------

    /**
     * ShiroFilterFactoryBean 处理拦截资源文件问题
     * 注意 单独一个 ShiroFilterFactoryBean 配置是或报错的
     * 因为在初始化 ShiroFilterFactoryBean 的时候需要注入 SecurityManager
     * Filter Chain 定义说明
     * 1、一个URL可以配置多个 Filter 使用逗号分隔
     * 2、当设置多个过滤器时 全部验证通过 才视为通过
     * 3、部分过滤器可指定参数 如 perms roles
     */
    @Bean(name = ["shiroFilter"])
    fun shiroFilter(): ShiroFilterFactoryBean {

        val shiroFilterFactoryBean = ShiroFilterFactoryBean()
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.securityManager = securityManager()
        // 登录地址
        shiroFilterFactoryBean.loginUrl = "/login"

        // 拦截器
        filters["myShiroFilter"] = MyShiroFilter()
        shiroFilterFactoryBean.filters = filters

        // 静态资源过滤;
        filterChainDefinitionMap["/assets/**"] = "anon"
        filterChainDefinitionMap["/language/**"] = "anon"
        filterChainDefinitionMap["/ueditor/upload"] = "anon"
        // 验证码
        filterChainDefinitionMap["/verifyImage**"] = "anon"
        // 登录页面
        filterChainDefinitionMap["/login**"] = "anon"
        // 处理登录
        filterChainDefinitionMap["/doLogin**"] = "anon"
        // 退出页面
        filterChainDefinitionMap["/logout**"] = "anon"

        // 错误页面
        filterChainDefinitionMap["/error**"] = "anon"
        filterChainDefinitionMap["/error/403**"] = "anon"
        filterChainDefinitionMap["/error/404**"] = "anon"

        // 配置记住我或认证通过可以访问的地址
        filterChainDefinitionMap["/**"] = "user,myShiroFilter"

        shiroFilterFactoryBean.filterChainDefinitionMap = filterChainDefinitionMap
        return shiroFilterFactoryBean
    }

    // -------------------------------------------------------------------------------------------------

}

// -----------------------------------------------------------------------------------------------------

// End ShiroConfiguration class

/* End of file ShiroConfiguration.kt */
/* Location: ./src/main/kotlin/wang/encoding/mroot/admin/common/shiro/ShiroConfiguration.kt */

// -----------------------------------------------------------------------------------------------------
// +----------------------------------------------------------------------------------------------------
// |                           ErYang出品 属于小极品  O(∩_∩)O~~   共同学习    共同进步
// +----------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------
